//
//  RxOperators.swift
//  TestSwift
//
//  Created by Song on 2018/9/17.
//  Copyright © 2018年 Song. All rights reserved.
//

import RxSwift
import RxCocoa
import UIKit

// 双向绑定
infix operator <-> : DefaultPrecedence

func nonMarkedText(_ textInput: UITextInput) -> String? {
    let start = textInput.beginningOfDocument
    let end = textInput.endOfDocument
    
    guard let rangeAll = textInput.textRange(from: start, to: end),
        let text = textInput.text(in: rangeAll) else {
            return nil
    }
    
    guard let markedTextRange = textInput.markedTextRange else {
        return text
    }
    
    guard let startRange = textInput.textRange(from: start, to: markedTextRange.start),
        let endRange = textInput.textRange(from: markedTextRange.end, to: end) else {
            return text
    }
    
    return (textInput.text(in: startRange) ?? "") + (textInput.text(in: endRange) ?? "")
}

func <-> <Base>(textInput: TextInput<Base>, behavior: BehaviorRelay<String>) -> Disposable {
    let bindToUIDisposable = behavior.asObservable()
        .bind(to: textInput.text)
    let bindToVariable = textInput.text
        .subscribe(onNext: { [weak base = textInput.base] n in
            guard let base = base else {
                return
            }
            
            let nonMarkedTextValue = nonMarkedText(base)
            if let nonMarkedTextValue = nonMarkedTextValue, nonMarkedTextValue != behavior.value {
                behavior.accept(nonMarkedTextValue)
            }
            }, onCompleted:  {
                bindToUIDisposable.dispose()
        })
    
    return Disposables.create(bindToUIDisposable, bindToVariable)
}

func <-> <T>(property: ControlProperty<T>, behavior: BehaviorRelay<T>) -> Disposable {
    let bindToUIDisposable = behavior.asObservable()
        .bind(to: property)
    let bindToVariable = property
        .subscribe(onNext: { n in
            behavior.accept(n)
        }, onCompleted:  {
            bindToUIDisposable.dispose()
        })
    
    return Disposables.create(bindToUIDisposable, bindToVariable)
}

func <-> <T>(behavior1: (behavior: BehaviorRelay<T>, skip: UInt), behavior2: (behavior: BehaviorRelay<T>, skip: UInt)) -> Disposable where T: Equatable {
    let disposable1 = behavior1.behavior.skip(Int(behavior1.skip)).bind { (data) in
        if data != behavior2.behavior.value {
            behavior2.behavior.accept(data)
        }
    }
    
    let disposable2 = behavior2.behavior.skip(Int(behavior2.skip)).bind { (data) in
        if data != behavior1.behavior.value {
            behavior1.behavior.accept(data)
        }
    }

    return Disposables.create(disposable1, disposable2)
}
